package qc.module.cms.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import qc.common.core.constants.QCAuthConstant;
import qc.common.core.exception.QCPromptException;
import qc.module.cms.dto.category.*;
import qc.module.cms.service.CategoryDeptService;
import qc.module.cms.service.CategoryService;
import qc.module.platform.dto.dept.DeptSimpleDto;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * CMS栏目控制器
 *
 * @author QuCheng Tech
 * @since 2023/5/26
 */
@RestController
@RequestMapping("/category")
public class CategoryController {
    private CategoryService categoryService;

    @Autowired
    public void setCategoryService(CategoryService categoryService) {
        this.categoryService = categoryService;
    }

    private CategoryDeptService categoryDeptService;

    @Autowired
    public void setCategoryDeptService(CategoryDeptService categoryDeptService) {
        this.categoryDeptService = categoryDeptService;
    }

    @Autowired
    HttpServletRequest request;

    //是否为逻辑删除，为true表示逻辑删除--修改记录标记，为false表示物理删除--从数据库表中删除记录
    private static final boolean isLogicDelete = false;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    //栏目支持的最大层级数
    private static final  Integer maxCategoryLevel = 0x2;

    /**
     * 查询栏目详情
     *
     * @param condition 查询条件
     * @return 栏目集合
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/listdetail", method = {RequestMethod.POST})
    public List<CategoryDto> queryListDetail(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //如果查询条件中指定了根据部门进行过滤，需要获取用户所在部门作为查询条件传入
        if (condition != null && condition.isIsdept()) {
            //根据token获取用户id
            //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
            String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
            //微服务调用uac，获取用户ID
            //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
            List<DeptSimpleDto> depts = getUserValidDepts(token);
            if (depts != null && depts.size() > 0x0) {
                userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
            }
        }

        return categoryService.queryListDetail(condition, userDeptIds);
    }

    /**
     * 查询栏目详情
     *
     * @param condition 查询条件
     * @return 栏目集合
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/treedetail", method = {RequestMethod.POST})
    public List<CategoryTreeDto> queryTreeDetail(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //如果查询条件中指定了根据部门进行过滤，需要获取用户所在部门作为查询条件传入
        if (condition != null && condition.isIsdept()) {
            //根据token获取用户id
            //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
            String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
            //微服务调用uac，获取用户ID
            //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
            List<DeptSimpleDto> depts = getUserValidDepts(token);
            if (depts != null && depts.size() > 0x0) {
                userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
            }
        }

        return categoryService.queryTreeDetail(condition, userDeptIds, maxCategoryLevel);
    }

    /**
     * 根据token获取用户所在项目中所有有效的部门
     *
     * @param token 用户登录得到的Token
     * @return 部门简要信息集合
     * @author QuCheng Tech
     * @since 2023/5/31
     */
    public List<DeptSimpleDto> getProjectValidDepts(String token) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(QCAuthConstant.TOKEN_HEADER_KEY, token);

        ServiceInstance service = discoveryClient.getInstances("module-platform").get(0);
        String url = "http://" + service.getHost() + ":" + service.getPort() + "/dept/projectvalid";

        HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
        ParameterizedTypeReference<List<DeptSimpleDto>> responseType = new ParameterizedTypeReference<List<DeptSimpleDto>>() {
        };

        ResponseEntity<List<DeptSimpleDto>> response = restTemplate.exchange(
                url,//获取资源的地址
                HttpMethod.GET,
                formEntity,
                responseType
        );
        List<DeptSimpleDto> resultDto = response.getBody();
        return resultDto;
    }

    /**
     * 根据token获取用户所在的有效的部门
     *
     * @param token 用户登录得到的Token
     * @return 部门简要信息集合
     * @author QuCheng Tech
     * @since 2023/5/31
     */
    public List<DeptSimpleDto> getUserValidDepts(String token) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(QCAuthConstant.TOKEN_HEADER_KEY, token);

        ServiceInstance service = discoveryClient.getInstances("module-platform").get(0);
        String url = "http://" + service.getHost() + ":" + service.getPort() + "/dept/uservalid";

        HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
        ParameterizedTypeReference<List<DeptSimpleDto>> responseType = new ParameterizedTypeReference<List<DeptSimpleDto>>() {
        };

        ResponseEntity<List<DeptSimpleDto>> response = restTemplate.exchange(
                url,//获取资源的地址
                HttpMethod.GET,
                formEntity,
                responseType
        );
        List<DeptSimpleDto> resultDto = response.getBody();

        return resultDto;
    }

    /**
     * 查询栏目列表，返回简要信息（仅包含ID、名称和层级）；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     *
     * @param condition 查询条件
     * @return 用户信息集合
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/listsimple", method = {RequestMethod.POST})
    public List<CategorySimpleDto> queryListSimple(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //如果查询条件中指定了根据部门进行过滤，需要获取用户所在部门作为查询条件传入
        if (condition != null && condition.isIsdept()) {
            //根据token获取用户id
            //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
            String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
            //微服务调用uac，获取用户ID
            //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
            List<DeptSimpleDto> depts = getUserValidDepts(token);
            if (depts != null && depts.size() > 0x0) {
                userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
            }
        }

        return categoryService.queryListSimple(condition, userDeptIds);
    }

    /**
     * 查询栏目列表，返回简要信息（仅包含ID、名称和层级）；查询条件可以为空，条件中可指定是否包含所有状态的栏目、根据部门进行过滤条件；
     * 返回结果包括用户所在部门有权限的栏目、不按部门控制权限的栏目、有子栏目权限但父栏目不在返回结果中的栏目
     *
     * @param condition 查询条件
     * @return 用户信息集合
     * @author QcCheng Tech
     * @since 2024/1/11
     */
    @RequestMapping(value = "/getvalidlistsimple", method = {RequestMethod.POST})
    public List<CategorySimpleDto> queryValidListSimple(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //根据token获取用户id
        //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
        //微服务调用uac，获取用户ID
        //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
        List<DeptSimpleDto> depts = getUserValidDepts(token);
        //不管查询条件中是否指定了根据部门进行过滤，都获取用户所在部门作为查询条件传入
        if (depts != null && depts.size() > 0x0) {
            userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
        }

        return categoryService.queryDtoListSimple(condition,userDeptIds,maxCategoryLevel);
    }

    /**
     * 查询栏目树结构简要信息
     * 返回结果包括用户所在部门有权限的栏目、不按部门控制权限的栏目、有子栏目权限但父栏目不在返回结果中的栏目
     *
     * @param condition 查询条件
     * @return 用户信息集合
     * @author QcCheng Tech
     * @since 2023/5/26
     * @update 2024/1/11
     */
    //@RequestMapping(value = "/treesimple", method = {RequestMethod.POST})
    //public List<CategoryTreeSimpleDto> queryTreeSimple(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
    //    List<Integer> userDeptIds = null;
    //    //如果查询条件中指定了根据部门进行过滤，需要获取用户所在部门作为查询条件传入
    //    if (condition != null && condition.isIsdept()) {
    //        //根据token获取用户id
    //        //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
    //        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
    //        //微服务调用uac，获取用户ID
    //        //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
    //        List<DeptSimpleDto> depts = getUserValidDepts(token);
    //        if (depts != null && depts.size() > 0x0) {
    //            userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
    //        }
    //    }
    //
    //    return categoryService.queryTreeSimple(condition, userDeptIds, 0x2);
    //}
    @RequestMapping(value = "/treesimple", method = {RequestMethod.POST})
    public List<CategoryTreeSimpleDto> queryTreeSimple(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //根据token获取用户id
        //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
        //微服务调用uac，获取用户ID
        //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
        List<DeptSimpleDto> depts = getUserValidDepts(token);
        //不管查询条件中是否指定了根据部门进行过滤，都获取用户所在部门作为查询条件传入
        if (depts != null && depts.size() > 0x0) {
            userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
        }

        return categoryService.queryTreeSimple(condition, userDeptIds, maxCategoryLevel);
    }

    /**
     * 获取指定栏目信息
     *
     * @param id 栏目ID
     * @return 栏目信息
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/get", method = {RequestMethod.GET})
    public CategoryDto getByParam(@RequestParam int id) throws QCPromptException {
        return categoryService.get(id, false);
    }

    /**
     * 获取指定栏目信息
     *
     * @param id 栏目ID
     * @return 栏目信息
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/get/{id}", method = {RequestMethod.GET})
    public CategoryDto getByPath(@PathVariable(required = true) int id) throws QCPromptException {
        return categoryService.get(id, false);
    }

    /**
     * 新增
     *
     * @param dto 栏目
     * @return 成功返回null
     * @author QcCheng Tech
     * @since 2023/5/25
     */
    @RequestMapping(value = "/add", method = {RequestMethod.POST})
    public String add(@RequestBody CategoryAddDto dto) {
        return categoryService.add(dto,maxCategoryLevel);
    }

    /**
     * 修改
     *
     * @param dto 栏目
     * @return 成功返回null
     * @author QcCheng Tech
     * @since 2023/5/25
     */
    @RequestMapping(value = "/update", method = {RequestMethod.PUT, RequestMethod.POST})
    public String update(@RequestBody CategoryDto dto) {
        return categoryService.update(dto,maxCategoryLevel);
    }

    /**
     * 删除
     *
     * @param id 栏目ID
     * @return 成功返回null
     * @author QcCheng Tech
     * @since 2023/5/25
     */
    @RequestMapping(value = "/delete", method = {RequestMethod.DELETE})
    public String deleteByParam(@RequestParam int id) {
        return categoryService.delete(id, isLogicDelete);
    }

    /**
     * 删除
     *
     * @param id 栏目ID
     * @return 成功返回null
     * @author QcCheng Tech
     * @since 2023/5/25
     */
    @RequestMapping(value = "/delete/{id}", method = {RequestMethod.DELETE})
    public String deleteByPath(@PathVariable(required = true) int id) {
        return categoryService.delete(id, isLogicDelete);
    }

    /**
     * 获取栏目部门配置
     *
     * @param ids 栏目ID集合，可批量获取设置
     * @return 栏目部门配置
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/getdepts", method = {RequestMethod.GET, RequestMethod.POST})
    public List<CategoryDeptDto> getDepts(@RequestBody List<Integer> ids) throws QCPromptException {
        //在此需要调用platform微服务获取部门/组织信息
        String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
        List<DeptSimpleDto> depts = getProjectValidDepts(token);

        //获取单个栏目的部门关联关系
        //return categoryDeptService.getDepts(id, depts);
        //获取多个栏目的部门关联关系，多个栏目需要对栏目取交集
        return categoryDeptService.getDepts(ids, depts);
    }

    /**
     * 设置栏目部门配置
     *
     * @param dto 栏目部门配置
     * @return 成功返回null
     * @author QcCheng Tech
     * @since 2023/5/26
     */
    @RequestMapping(value = "/depts", method = {RequestMethod.POST})
    public String setDepts(@RequestBody CategoryDeptSetDto dto) {
        return categoryDeptService.setDepts(dto);
    }


    /**
     *查询条件中指定是否包含所有状态的栏目、根据部门进行过滤条件；结果以TreeTable组件要求的数据格式返回各栏目的详细信息；
     *
     * @param condition: 查询条件
     * @return List<CategoryTreeTableDetailDto> 返回各栏目的详细信息
     * @author QcCheng Tech
     * @date 2023/8/2 
     */
    @RequestMapping(value = "/treetabledetail", method = {RequestMethod.POST})
    public List<CategoryTreeTableDetailDto> queryTreeTableDetail(@RequestBody CategoryQueryConditionDto condition) throws QCPromptException {
        List<Integer> userDeptIds = null;
        //如果查询条件中指定了根据部门进行过滤，需要获取用户所在部门作为查询条件传入
        if (condition != null && condition.isIsdept()) {
            //根据token获取用户id
            //在platform中使用直接调用，在其他项目中使用微服务之间调用方式
            String token = request.getHeader(QCAuthConstant.TOKEN_HEADER_KEY);
            //微服务调用uac，获取用户ID
            //判断查询条件，如果需要根据部门过滤，使用微服务调用根据用户ID获取部门集合信息
            List<DeptSimpleDto> depts = getUserValidDepts(token);
            if (depts != null && depts.size() > 0x0) {
                userDeptIds = depts.stream().map(p -> p.getId()).collect(Collectors.toList());
            }
        }
        return categoryService.queryTreeTableDetail(condition, userDeptIds, 0x2);
    }
}
